<template>
  <a-tabs v-model:activeKey="tabKey" type="editable-card" @edit="onEdit" hideAdd>
    <a-tab-pane
      forceRender
      v-for="(item, index) in goodsModel"
      :key="item.key"
      :tab="item.title"
      :closable="item.closable"
    >
      <Cropper
        :file="item.cropper.file"
        :isFirst="isFirst"
        :crop-size="clientType === PlatformEnum.PC ? [480, 320] : [320, 320]"
        :fixed-number="clientType === PlatformEnum.PC ? [3, 2] : [1, 1]"
        v-model:show="item.cropper.show"
        @confirm="handleCropper(item, index, $event)"
      />
      <a-form-item
        label="商品图片"
        :name="[validKey, index, 'fileList']"
        :rules="{
          required: showRequirePicRule,
          message: '请上传商品图片',
          trigger: 'change'
        }"
      >
        <div class="flex">
          <a-upload
            class="uploader"
            accept="image/jpeg,image/jpg,image/png,image/webp"
            :before-upload="($event) => beforeUpload(item, $event)"
            list-type="picture-card"
            v-model:file-list="item.fileList"
            @preview="handlePreview(item, $event)"
            @remove="handleImgRemove(item)"
            :disabled="isFirst === isFirstEnum.Other"
          >
            <div v-if="(item.fileList || []).length < 1">
              <inbox-outlined class="text-30 text-red-400" />
              <div class="mt-2">上传图片</div>
            </div>
          </a-upload>
          <div class="flex-1">
            <p class="mb-0 text-gray-500 font-bold">请阅读上传要求:</p>
            <p class="mb-0 text-gray-500">图片尺寸：{{ clientType === PlatformEnum.PC ? '3:2' : '1:1' }}</p>
            <p class="mb-0 text-gray-500">格式：JPG、JPEG、PNG格式</p>
            <p class="mb-0 text-gray-500">大小：2MB以内</p>
          </div>
        </div>
      </a-form-item>
      <a-form-item
        label="商品名称"
        v-if="clientType === PlatformEnum.PC && !isGift"
        :name="[validKey, index, 'name']"
        :rules="{
          required: showRequirePicRule,
          trigger: ['change', 'blur'],
          validator: (...args) => checkGoodsName(...args, item)
        }"
      >
        <a-input v-model:value.trim="item.name" placeholder="请输入商品名称" />
      </a-form-item>
      <a-form-item
        v-if="clientType === PlatformEnum.PC && !isGift"
        label="商品描述"
        :name="[validKey, index, 'info']"
        :rules="{
          required: showRequirePicRule,
          trigger: ['change', 'blur'],
          validator: (...args) => checkGoodsInfo(...args, item)
        }"
      >
        <a-textarea
          :auto-size="{ minRows: 5, maxRows: 5 }"
          v-model:value.trim="item.info"
          placeholder="请输入商品描述"
        />
      </a-form-item>
    </a-tab-pane>
  </a-tabs>
</template>

<script lang="ts" setup name="PromotionGoods">
import { computed } from 'vue'
import { GoodsFields } from '@/views/promotion/interface'
import { message, Upload, UploadFile } from 'ant-design-vue'
import { base64ToFile, byteLength, fileToBase64, getMime, makeShortId, setBase64Prefix } from '@/utils'
import { FileType } from 'ant-design-vue/es/upload/interface'
import { last } from 'lodash-es'
import { useVModel } from '@vueuse/core'
import { InboxOutlined } from '@ant-design/icons-vue'
import Cropper from '@/components/cropper/index.vue'
import type { Rule } from 'ant-design-vue/es/form'
import { PlatformEnum } from '@/core/enums/platform'
import { isFirstEnum } from '@/store/usePromotionStore'

interface Props {
  orderWordId?: number
  goods: GoodsFields[]
  showRequirePicRule: boolean
  word: string
  activeKey: number
  clientType: PlatformEnum
  addCreative: (goodsModel: GoodsFields[], count: number) => void
  isGift: boolean
  isFirst: isFirstEnum
}

const props = withDefaults(defineProps<Props>(), {
  goods: () => [],
  word: '',
  activeKey: 1,
  showRequirePicRule: false,
  clientType: PlatformEnum.PC,
  addCreative: () => {}
})

const goodsModel = useVModel(props, 'goods')
const tabKey = useVModel(props, 'activeKey')
const validKey = computed(() => {
  if (props.clientType === PlatformEnum.PC) {
    return 'pcGoods'
  } else {
    return 'wapGoods'
  }
})

function beforeUpload(pane: GoodsFields, file: UploadFile) {
  const findResult = props.goods.find((item) => item.fileList?.[0]?.originFileObj?.name === file.name)
  if (findResult) {
    message.error('上传图片重复，为了让客户看到您的更多产品/服务，请更换图片再提交。')
    return Upload.LIST_IGNORE
  } else {
    pane.cropper.file = file
    pane.cropper.show = true
    return Upload.LIST_IGNORE
  }
}

// 判断图片集的base64是否相同
function compareSimilar(base64: string) {
  const hasPicture = goodsModel.value.some((item) => (item.fileList || []).length > 0)
  if (hasPicture) {
    return goodsModel.value
      .filter((item) => (item.fileList || []).length > 0)
      .map((item) => item.imageContent)
      .concat(base64)
      .some((x, i, arr) => arr.findIndex((y) => y === x) !== i)
  }
  return false
}

async function handleCropper(good: GoodsFields, index: number, blob: Blob) {
  good.pictureName = `${makeShortId()}${props.word.slice(0, 3)}.${getMime(good.cropper.file!.name)}`
  // 将Blob文件转换成File格式
  let file = new File([blob], good.pictureName, {
    type: blob.type
  })

  let base64 = await fileToBase64(file)
  const content = base64.split(',')
  content.shift()
  base64 = content.join()

  if (compareSimilar(base64)) {
    return message.error('上传图片重复，为了让客户看到您的更多产品/服务，请更换图片再提交。')
  }

  good.imageContent = base64
  good.fileList = [
    {
      uid: (good.cropper.file as UploadFile).uid,
      name: good.pictureName,
      status: 'done',
      originFileObj: file as FileType
    }
  ]

  good.cropper.show = false
}

function handleImgRemove(good: GoodsFields) {
  good.fileList = []
  good.pictureName = ''
  good.imageContent = ''
}

function handlePreview(good: GoodsFields, file: UploadFile) {
  if (file.preview) {
    good.cropper.file = base64ToFile(setBase64Prefix(file.preview), file.name)
  } else {
    good.cropper.file = file.originFileObj
  }

  good.cropper.show = true
}

function onEdit(targetKey: number | MouseEvent, action: string) {
  if (action === 'add') {
    props.addCreative(goodsModel.value, 1)
    tabKey.value = last(goodsModel.value)!.key
  } else {
    remove(targetKey as number)
  }
}

function remove(targetKey: number) {
  const i = goodsModel.value.findIndex((g) => g.key === targetKey)

  if (i > -1) {
    goodsModel.value.splice(i, 1)

    if (goodsModel.value.length && tabKey.value === targetKey) {
      if (i > 0) {
        tabKey.value = goodsModel.value[i - 1].key
      } else {
        tabKey.value = goodsModel.value[0].key
      }
    }
  }
}

function checkGoodsName(_rule: Required<Rule>, value: string, callback: Function, item: GoodsFields) {
  const min = 2
  const max = 18

  if (value) {
    const repeat = goodsModel.value.some((g) => {
      if (g.key !== item.key) {
        return g.name === item.name
      } else {
        return false
      }
    })

    if (repeat) {
      return Promise.reject('商品名称不能重复')
    }

    const len = byteLength(value)

    if (min - len > 0) {
      return Promise.reject(`商品名称还差${Math.abs(min - len)}个字节`)
    }

    if (max - len < 0) {
      return Promise.reject(`商品名称超出${Math.abs(max - len)}个字节`)
    }

    return Promise.resolve()
  } else if (props.showRequirePicRule) {
    return Promise.reject('商品名称不能为空')
  } else {
    if (item.fileList && item.fileList.length > 0) {
      return Promise.reject(`请输入商品名称，名称在${min}到${max}字节内`)
    } else {
      return Promise.resolve()
    }
  }
}

function checkGoodsInfo(_rule: Required<Rule>, value: string, callback: Function, item: GoodsFields) {
  const min = 2
  const max = 18

  if (value) {
    const repeat = goodsModel.value.some((g) => {
      if (g.key !== item.key) {
        return g.info === item.info
      } else {
        return false
      }
    })

    if (repeat) {
      return Promise.reject('商品描述不能重复')
    }

    const len = byteLength(value)

    if (min - len > 0) {
      return Promise.reject(`商品描述还差${Math.abs(min - len)}个字节`)
    }

    if (max - len < 0) {
      return Promise.reject(`商品描述超出${Math.abs(max - len)}个字节`)
    }

    return Promise.resolve()
  } else if (props.showRequirePicRule) {
    return Promise.reject('商品描述不能为空')
  } else {
    if (item.fileList && item.fileList.length > 0) {
      return Promise.reject(`请输入商品描述，名称在${min}到${max}字节内`)
    } else {
      return Promise.resolve()
    }
  }
}
</script>

<style lang="scss" scoped>
.uploader {
  width: auto;
  ::v-deep(.ant-upload-list-picture-card-container) {
    margin: 0 8px 0 0;
  }
}
</style>
